在寫 Dockerfile 或使用 docker run
時,我們使用 CMD
來執行指令。Docker 還設計了另一個類似的設定叫 ENTRYPOINT
。活用這兩個設定將能讓 Docker image 使用更加靈活。
CMD
的設計首先要強調一個重要的概念--container 就是 process。啟動 container 背後的原理就是啟動 process。
因此 Docker CMD
有個特性是,後面的設定會覆蓋前面的設定。比方說,以 alpine:3.12 的 Dockerfile 為例
FROM scratch
ADD alpine-minirootfs-3.12.0-x86_64.tar.gz /
CMD ["/bin/sh"]
這裡 CMD
的設定是 /bin/sh
。FROM 它的 image 如 php:7.4-alpine:
FROM alpine:3.12
# 略
CMD ["php", "-a"]
有設定新的 CMD
時,它會以後設定的為主。
docker run
是類似的情境,它是最後一關,先再看一次 docker run
的語法:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
這裡的 [COMMAND]
指的就是 CMD
。在下 docker run
沒有帶 COMMAND
的時候,它會使用 Dockerfile 定義的 CMD
;如果有給,它就會覆蓋 CMD
設定。
也就是,下面這幾個例子結果是一樣的:
# Alpine
docker run --rm -it alpine:3.12
docker run --rm -it alpine:3.12 /bin/sh
# Node
docker run --rm -it php:7.4-alpine
docker run --rm -it php:7.4-alpine php -a
若想在 container 上執行其他指令,只要在後面接 COMMAND 即可:
# Alpine
docker run --rm -it alpine:3.12 ls
# Node
docker run --rm -it node:14-alpine node -v
這招在過去幾天裡很常拿來用,實際的意義就是取代 CMD
設定。
ENTRYPOINT
的設計ENTRYPOINT
跟 CMD
很像,一樣是啟動 container 的時候會用到,所以一樣也會有後面設定覆蓋的狀況。
以 mysql:8 為例:
# 略
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 3306 33060
CMD ["mysqld"]
若將啟動 container 當成是執行指令的話,那 docker run
與 ENTRYPOINT
的關係就像下面這樣
# 等於在容器內執行 docker-entrypoint.sh mysqld
docker run --rm -it mysql:8
# 等於在容器內執行 docker-entrypoint.sh bash
docker run --rm -it mysql:8 bash
這時,我們可以做一個實驗:
# 使用 bash 進入 container
docker run --rm -it mysql:8 bash
# 在 container 裡執行 ENTRYPOINT + bash
docker-entrypoint.sh bash
# 在 container 裡執行 ENTRYPOINT + mysqld
docker-entrypoint.sh mysqld
沒錯,這就跟上面直接執行 docker run
結果一樣。相信這個實驗做完,就能理解 CMD 與 ENTRYPOINT 的差異與用法了。
了解 CMD 與 ENTRYPOINT 的設計後,接著就能開始設計更多變化的 image 了。
筆者病還沒好,已盡力打文章了。
不好意思 想問一下
如果只有 ENTRYPOINT
但沒有 CMD
同時 docker run
不給 CMD
這代表什麼意思呢 ?
不能執行,Docker Daemon 會跟你說:
docker: Error response from daemon: No command specified.
See 'docker run --help'.
等等,我好像誤會意義了。
有 ENTRYPOINT 沒有 CMD,這代表它只會拿 ENTRYPOINT 來執行,24天有個表格可以參考
原來如此! 感謝
不過想再提問兩點
ENTRYPOINT
和 CMD
誰先執行,誰後執行 ?
還是說 CMD
只是單純給 ENTRYPOINT
當作參數 ?
有看過網路上一些寫法
// 第一種,用 ENTRYPOINT,和用 CMD
ENTRYPOINT ["/bin/cat"]
CMD ["/etc/passwd"]
// 第二種,只用 ENTRYPOINT,不用 CMD
ENTRYPOINT ["/bin/cat", "/etc/passwd"]
// 第三種,不用 ENTRYPOINT,只用 CMD
CMD ["/bin/cat", "/etc/passwd"]
這三種寫法有什麼差別嗎 ?
還是他們間有什麼優劣嗎 ?
沒有什麼優劣,單純只是排先後順序的問題
差別你剛分享的三種寫法,結果都是一樣的,所以一個是寫法上的差異
另一個就是 CMD 要取代比較容易,所以常會調整的指令可以放 CMD,ENTRYPOINT 則是放不常調整的。
原來如此! 感謝您